package application

import (
	"context"
	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
	"io"
	"net/http"
	"os"
	"time"
	"usbipproxy/common"
	"usbipproxy/domain/dto"
)

type ServerImpl struct {
	listenAddr string
	r          *gin.Engine
	httpSvc    HttpMsgHandleService
	server     *http.Server
	close      bool
}

func (s *ServerImpl) Start() error {

	if os.Getenv("ENV") != "prod" {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}

	gin.DefaultWriter = &common.GinLogrusWriter{}
	gin.DefaultErrorWriter = &common.GinLogrusWriter{}

	router := gin.Default()
	router.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Max-Age", "86400")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

		// 处理预检请求
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}

		c.Next()
	})

	router.Use(gin.LoggerWithConfig(gin.LoggerConfig{Output: io.Discard})) // 禁用默认日志)

	router.POST("/api/usbip/list", s.usbIpListHandler)
	router.GET("/api/usbip/list", s.usbIpListHandler)
	router.POST("/api/usbip/attach", s.usbIpAttachHandler)
	router.GET("/api/usbip/attach", s.usbIpAttachHandler)
	router.POST("/api/usbip/detach", s.usbIpDetachHandler)
	router.GET("/api/usbip/detach", s.usbIpDetachHandler)
	router.GET("/api/usbip/client_info", s.clientInfoHandler)
	router.GET("/api/usbip/dispatch_list", s.usbIpDispatchList)
	router.GET("/api/usbip/device_info", s.deviceInfoHandler)

	s.r = router
	// 组合监听地址
	//addr := fmt.Sprintf("%s:%d", s.host, s.port)

	go func() {
		server := &http.Server{
			Addr:    s.listenAddr,
			Handler: router,
		}
		s.server = server

		// 3. 使用协程启动服务
		go func() {
			if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
				log.Fatalf("server start %s fail: %v", s.listenAddr, err)
			}
		}()
	}()
	return nil
}

func (s *ServerImpl) Stop() error {
	if s.close {
		return nil
	}
	s.close = true

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	if err := s.server.Shutdown(ctx); err != nil {
		log.Fatalf("http server exit err: %v", err)
	}

	log.Infof("http server exit")
	return nil
}

func (s *ServerImpl) usbIpListHandler(c *gin.Context) {
	var req dto.UsbIpListReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	res, err := s.httpSvc.UsbIpList(&req)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}
	c.JSON(200, res) // /*gin.H{"data": res}*/)
}

func (s *ServerImpl) clientInfoHandler(c *gin.Context) {
	var req dto.ClientInfoReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	res, err := s.httpSvc.ClientInfo(&req)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}
	c.JSON(200, res) // /*gin.H{"data": res}*/)
}

func (s *ServerImpl) usbIpAttachHandler(c *gin.Context) {
	var req dto.UsbIpAttachReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	res, err := s.httpSvc.UsbIpAttach(&req)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}
	c.JSON(200, res) // /*gin.H{"data": res}*/)
}

func (s *ServerImpl) usbIpDetachHandler(c *gin.Context) {
	var req dto.UsbIpDetachReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	res, err := s.httpSvc.UsbIpDetach(&req)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}
	c.JSON(200, res) // /*gin.H{"data": res}*/)
}

func (s *ServerImpl) usbIpDispatchList(c *gin.Context) {
	var req dto.DispatchListReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	res, err := s.httpSvc.DispatchList(&req)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}
	c.JSON(200, res) // /*gin.H{"data": res}*/)
}

func (s *ServerImpl) usbIpUnBind(c *gin.Context) {
	var req dto.UsbipUnbindReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	res, err := s.httpSvc.UsbipUnbind(&req)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}
	c.JSON(200, res) // /*gin.H{"data": res}*/)
}

func (s *ServerImpl) deviceInfoHandler(c *gin.Context) {
	var req dto.DeviceInfoReq
	if err := c.ShouldBind(&req); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	res, err := s.httpSvc.DeviceInfo(&req)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 1,
			"msg":  err.Error(),
		})
		return
	}
	c.JSON(200, res) // /*gin.H{"data": res}*/)
}

func NewServerImpl(listenAddr string, httpSvc HttpMsgHandleService) HttpServer {
	return &ServerImpl{
		listenAddr: listenAddr,
		httpSvc:    httpSvc,
	}
}
